﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace grid_test
{
    /// <summary>
    /// 可分组的列 (该列必须是 Grid 的第一列)
    /// </summary>
    public class DataGridViewGroupColumn : DataGridViewTextBoxColumn
    {
        public DataGridViewGroupColumn()
        {
            CellTemplate = new DataGridViewGroupCell();
            ReadOnly = false;
        }
        public override bool ReadOnly
        {
            get
            {
                return base.ReadOnly;
            }
            set
            {
                base.ReadOnly = value;
            }
        }
        public override DataGridViewCell CellTemplate
        {
            get
            {
                return base.CellTemplate;
            }
            set
            {
                if ((value != null) && !(value is DataGridViewGroupCell))
                {
                    throw new InvalidCastException("Need System.Windows.Forms.DataGridViewGroupCell");
                }
                base.CellTemplate = value;
            }

        }
    }


    public class DataGridViewGroupCell : DataGridViewTextBoxCell
    {

        const int PLUS_WIDTH = 40;
        Rectangle groupPlusRect;
        public DataGridViewGroupCell()
        {
            groupLevel = 1;
        }
        int groupLevel;
        public int GroupLevel
        {
            get { return groupLevel; }
            set { groupLevel = value; }
        }
        string sname = string.Empty;

        DataGridViewGroupCell parentCell = null;
        public DataGridViewGroupCell ParentCell
        {
            get
            {
                return parentCell;
            }

        }

        private bool collapsed;

        public bool Collapsed
        {
            get { return collapsed; }
        }

        private List<DataGridViewGroupCell> childCells = null;
        public DataGridViewGroupCell[] ChildCells
        {
            get
            {
                if (childCells == null)
                    return null;
                return childCells.ToArray();
            }
        }

        public Rectangle GroupPlusRect
        {
            get
            {
                return groupPlusRect;
            }
        }

        bool bPaint = true;

        public bool BPaint
        {
            get { return bPaint; }
            set { bPaint = value; }
        }
        public int AddChildCell(DataGridViewGroupCell cell)
        {
            return AddChildCellRange(new DataGridViewGroupCell[] { cell });
        }

        public int AddChildCellRange(DataGridViewGroupCell[] cells)
        {
            bool needRedraw = false;
            if (childCells == null)
            {
                childCells = new List<DataGridViewGroupCell>();
                needRedraw = true;
            }
            foreach (DataGridViewGroupCell cell in cells)
            {
                childCells.Add(cell);
                cell.groupLevel = groupLevel + 1;
                //cell.sname = cell[0];
                cell.sname = childCells.Count.ToString();

                string s = string.Empty;
            }

            if (needRedraw)
                DataGridView.InvalidateCell(this);
            
            return childCells.Count;
        }

        protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            if (!bPaint)
            {
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
                return;
            }
            Pen gridPen = new Pen(DataGridView.GridColor);
            Brush bruBK = new SolidBrush(cellStyle.BackColor);
            int width = groupLevel * PLUS_WIDTH;
            Rectangle rectLeft = new Rectangle(cellBounds.Left, cellBounds.Top - 1, width, cellBounds.Height);
            cellBounds.X += width;
            cellBounds.Width -= width;
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);

            PaintGroupPlus(graphics, gridPen, bruBK, cellStyle, rectLeft, collapsed);

            gridPen.Dispose();
            gridPen = null;

            bruBK.Dispose();
            bruBK = null;
        }

        private void PaintGroupPlus(Graphics graphics, Pen gridPen, Brush bruBK, DataGridViewCellStyle cellStyle, Rectangle rectLeft, bool collapsed)
        {
            graphics.FillRectangle(bruBK, rectLeft);
            int left = rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH;
            gridPen.Color = Color.DarkGray;
            gridPen.DashStyle = DashStyle.DashDotDot;
            if (groupLevel > 1)
            {
                graphics.DrawLine(gridPen, rectLeft.Right - PLUS_WIDTH, (rectLeft.Top + rectLeft.Bottom) / 2, rectLeft.Right, (rectLeft.Top + rectLeft.Bottom) / 2);//rectLeft.Right-PLUS_WIDTH
            }
            bool drawBottomLine = false;
            for (int i = 1; i < groupLevel; i++)
            {

                gridPen.Color = Color.DarkGray;
                gridPen.DashStyle = DashStyle.DashDotDot;


                if (i == 1)
                {
                    if (!IsLastCell(i))
                    {

                        if ((childCells != null && childCells.Count > 0))
                        {
                            graphics.DrawLine(gridPen, rectLeft.Right - i * PLUS_WIDTH, rectLeft.Top
                           , rectLeft.Right - i * PLUS_WIDTH, rectLeft.Bottom - rectLeft.Height / 2);

                        }
                        else
                            graphics.DrawLine(gridPen, rectLeft.Right - i * PLUS_WIDTH, rectLeft.Top
                       , rectLeft.Right - i * PLUS_WIDTH, rectLeft.Bottom);
                    }
                    else
                        graphics.DrawLine(gridPen, rectLeft.Right - i * PLUS_WIDTH, rectLeft.Top
                           , rectLeft.Right - i * PLUS_WIDTH, rectLeft.Bottom - rectLeft.Height / 2);
                }

                if (!drawBottomLine && IsLastCell(i))
                {

                    gridPen.Color = DataGridView.GridColor;
                    gridPen.DashStyle = DashStyle.Solid;

                    graphics.DrawLine(gridPen, rectLeft.Left + (i - 1) * PLUS_WIDTH, rectLeft.Bottom
                    , rectLeft.Left + groupLevel * PLUS_WIDTH, rectLeft.Bottom);
                    drawBottomLine = true;
                    break;
                }
            }

            gridPen.DashStyle = DashStyle.Solid;

            if (childCells != null && childCells.Count > 0)
            {
                groupPlusRect = new Rectangle((groupLevel - 1) * PLUS_WIDTH + rectLeft.Left + (PLUS_WIDTH - 2) / 2
                    , rectLeft.Top + (rectLeft.Height - 2) / 2, 12, 12);
                graphics.DrawRectangle(gridPen, groupPlusRect);//画一个矩形框

                graphics.DrawLine(Pens.Black, groupPlusRect.Left + 3, groupPlusRect.Top + groupPlusRect.Height / 2
                , groupPlusRect.Right - 3, groupPlusRect.Top + groupPlusRect.Height / 2);
                if (collapsed)
                {
                    graphics.DrawLine(Pens.Black, groupPlusRect.Left + groupPlusRect.Width / 2, groupPlusRect.Top + 3
                , groupPlusRect.Left + groupPlusRect.Width / 2, groupPlusRect.Bottom - 3);
                }
            }
        }
        private bool IsLastCell(int level)
        {
            int row = DataGridView.Rows.GetNextRow(RowIndex, DataGridViewElementStates.None);
            if (row == -1)
                return true;
            DataGridViewGroupCell cel = DataGridView.Rows[row].Cells[0] as DataGridViewGroupCell;
            return (cel.GroupLevel == level);
        }

        private bool IsNextLevSame()
        {
            int row = DataGridView.Rows.GetNextRow(RowIndex, DataGridViewElementStates.None);
            if (row == -1)
                return false;
            DataGridViewGroupCell cel = DataGridView.Rows[row].Cells[0] as DataGridViewGroupCell;
            return (cel.GroupLevel == this.GroupLevel);
        }

        protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
        {
            Rectangle rect = DataGridView.GetCellDisplayRectangle(ColumnIndex, RowIndex, false);
            Point pt = new Point(rect.Left + e.Location.X, rect.Top + e.Location.Y);
            if (groupPlusRect.Contains(pt))
            {
                if (collapsed)
                {
                    Expand();
                }
                else
                {
                    Collapse();
                }
            }
            base.OnMouseDown(e);
        }
        public void Expand()
        {
            collapsed = false;
            ShowChild(true);
            base.DataGridView.InvalidateCell(this);
        }

        private void ShowChild(bool show)
        {
            if (childCells == null)
                return;
            foreach (DataGridViewGroupCell cel in childCells)
            {
                if (cel.RowIndex == -1)
                {
                    continue;
                }
                CurrencyManager cm = (CurrencyManager)this.DataGridView.BindingContext[DataGridView.DataSource];
                cm.SuspendBinding();

                DataGridView.Rows[cel.RowIndex].Visible = show;
                if (!cel.collapsed)
                    cel.ShowChild(show);
                cm.ResumeBinding();
            }
        }

        public void Collapse()
        {
            collapsed = true;
            ShowChild(false);
            base.DataGridView.InvalidateCell(this);
        }


        public void ExpandAll()
        {
            if (childCells == null)
                return;
            foreach (DataGridViewGroupCell cel in childCells)
            {
                cel.Expand();
                cel.ExpandAll();
            }
        }
    }
}
